﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.MathLib
{
    public class Ellipsoid3d : Solid3d
    {
        private double aRadius;
        private double bRadius;
        private double cRadius;
        private double startAngle;
        private double endAngle;
        private bool isClosed;
        public bool IsClosed { get => this.isClosed; set => this.SetSize(this.aRadius, this.bRadius, this.cRadius, this.startAngle, this.endAngle, value); }
        public Axis3dType Axis { get; set; } = Axis3dType.Z;
        public double ARadius { get => this.aRadius; set => this.SetSize(value, this.bRadius, this.cRadius, this.startAngle, this.endAngle,this.isClosed); }
        public double BRadius { get => this.bRadius; set => this.SetSize(this.aRadius , value , this.cRadius, this.startAngle, this.endAngle, this.isClosed); }
        public double CRadius { get => this.cRadius; set => this.SetSize(this.aRadius, this.bRadius, value, this.startAngle, this.endAngle, this.isClosed); }
        public double StartAngle { get => this.startAngle; set => this.SetSize(this.aRadius, this.bRadius, this.cRadius, value, this.endAngle, this.isClosed); }
        public double EndAngle { get => this.endAngle; set => this.SetSize(this.aRadius, this.bRadius, this.cRadius, this.startAngle, value, this.isClosed); }

        public Surface3d[] Surfaces;
        private TopoFaceModel topoFaceModel;
        public Ellipsoid3d(double aRadius = 10, double bRadius = 10, double cRadius = 10, double startAngle = 0, double endAngle = Utils.TwoPI,bool isClosed=true, int radialSegments = 32)
        {
            this.SetSize(aRadius, bRadius, cRadius,startAngle,endAngle,isClosed);
        }

        public Ellipsoid3d SetSize(double aRadius = 10, double bRadius = 10, double cRadius = 10, double startAngle = 0, double endAngle = Utils.TwoPI, bool isClosed = true, int radialSegments = 32)
        {
            if (topoFaceModel != null && (this.aRadius != aRadius || this.bRadius != bRadius || this.cRadius != cRadius ))
            {
                topoFaceModel = null;
            }
            this.aRadius = aRadius;
            this.bRadius = bRadius;
            this.cRadius = cRadius;
            this.startAngle = startAngle;
            this.endAngle = endAngle;
            this.isClosed = isClosed;
            return this;
        }
        private double normalize(double angle)
        {
            while (angle < 0) angle += Utils.TwoPI;
            while (angle > Utils.TwoPI) angle -= Utils.TwoPI;
            return angle;
        }
        public override TopoFaceModel CreateTopoModel()
        {
            if (topoFaceModel != null)
                return topoFaceModel;
            var aroundFaces = new List<Surface3d>();
            var halfAngle = normalize(this.endAngle - this.startAngle) / 2;
            var surface = new EllipsoidSurface3d(new Vector3(), this.aRadius,this.bRadius,this.cRadius,this.startAngle, this.startAngle+halfAngle);
            aroundFaces.Add(surface);
            var surface2 = new EllipsoidSurface3d(new Vector3(), this.aRadius, this.bRadius, this.cRadius, this.startAngle+ halfAngle, this.endAngle);
            aroundFaces.Add(surface2);
            if (IsClosed)
            {
                var acEl = new Ellipse3d();
                acEl.Center = new Vector3();
                acEl.StartAngle = this.StartAngle;
                acEl.EndAngle = this.EndAngle;
                acEl.RadiusX = this.aRadius;
                acEl.RadiusY = this.cRadius;
                acEl.Normal = new Vector3(0, -1, 0);
                var tps = acEl.GetPoints(1);
                var sp = tps.First();
                var sRadius = sp.DistanceTo(acEl.Center);
                var sNormal = sp.Clone().Sub(acEl.Center).Normalize();
                var sEl = new Ellipse3d();
                sEl.Center = acEl.Center;
                sEl.RadiusX = sRadius;
                sEl.RadiusY = bRadius;
                sEl.StartAngle = -Utils.HalfPI;
                sEl.EndAngle = Utils.HalfPI;
                sEl.Normal = sNormal.Cross(new Vector3(0, 1, 0));
                var sElps = sEl.GetPoints(1);
                var sl = new Line3d(sElps.Last().Clone(), sElps.First().Clone());
                var surface3 = new PlanarSurface3d(new Plane(sNormal.Clone().Negate()), new List<Curve3d>() { sEl, sl });
                aroundFaces.Add(surface3);
                var ep = tps.Last();
                var eRadius = ep.DistanceTo(acEl.Center);
                var eNormal = ep.Clone().Sub(acEl.Center).Normalize();
                var eEl = new Ellipse3d();
                eEl.Center = acEl.Center;
                eEl.RadiusX = eRadius;
                eEl.RadiusY = bRadius;
                eEl.StartAngle = -Utils.HalfPI;
                eEl.EndAngle = Utils.HalfPI;
                eEl.Normal = eNormal.Cross(new Vector3(0, 1, 0));
                var eElps = eEl.GetPoints(1);
                var el = new Line3d(eElps.Last().Clone(), eElps.First().Clone());
                var surface4 = new PlanarSurface3d(new Plane(eNormal.Clone()), new List<Curve3d>() { eEl, el });
                aroundFaces.Add(surface4);

            }
            this.Surfaces = aroundFaces.ToArray();
            this.topoFaceModel = new TopoFaceModel() { Surfaces = this.Surfaces.ToListEx() };
            return this.topoFaceModel;
        }
 
        public override Solid3d CreateMesh()
        {
            base.CreateMesh();
            this.Geometry.Groups[0].MaterialIndex = 0;
            this.Geometry.Groups[1].MaterialIndex = 1;
            this.Geometry.Groups[2].MaterialIndex = 2;
            this.Geometry.Groups[3].MaterialIndex = 3;
            this.Edge = new GeometryData();
            var v3Array = new double[3 * (33 * 33)];

            var idxArray = new ListEx<int>() { };
  
            this.Edge.Verteics = v3Array;
            this.Edge.Indics = idxArray.ToArray();
            return this;
        }
    }
}
